﻿using System;
using System.Collections.Generic;
using oModbus.Device;
using oModbus.Message;
using oModbus.Utility;

namespace oModbus
{
    /// <summary>
    /// 从机
    /// </summary>
    public class ModbusSlave : IModbusSlave
    {
        /// <summary>
        /// 从机Id
        /// </summary>
        public byte SlaveId { get; set; }
        /// <summary>
        /// 传输接口
        /// </summary>
        private readonly ITransmission _transmission;

        public ModbusSlave(byte unitId, ITransmission transmission)
        {
            SlaveId = unitId;
            _transmission = transmission;
            //_transmission = new SerialTransmission(port);
            _transmission.ReceivedMessageEvent += _transmission_ReceivedMessageEvent;
        }


        /// <summary>
        /// 校验
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private bool Verification(byte[] data)
        {
            byte[] crc1 = new List<byte>() { data[data.Length - 2], data[data.Length - 1] }.ToArray();
            List<byte> temp = new List<byte>();
            for (int i = 0; i < data.Length - 2; i++)
            {
                temp.Add(data[i]);
            }
            byte[] crc2 = temp.ToArray().CalculateCrc(); 
            return crc1[0] == crc2[0] && crc1[1] == crc2[1];

        }
        /// <summary>
        /// 接受数据
        /// </summary>
        /// <param name="data"></param>
        private void _transmission_ReceivedMessageEvent(byte[] data)
        {
            if (data.Length > 4)
            {
                if (Verification(data))
                {
                    ReceivedMessageEvent?.Invoke(data);
                    switch ((FunctionCode)data[1])
                    {
                        case FunctionCode.ReadCoil:

                            Handle(new ReadCoilRequest(data));
                            break;
                        case FunctionCode.ReadDiscreteInput:
                            Handle(new ReadDiscreteInputRequest(data));
                            break;
                        case FunctionCode.ReadHoldRegister:
                            Handle(new ReadHoldRegisterRequest(data));
                            break;
                        case FunctionCode.ReadInputRegister:
                            Handle(new ReadInputRegisterRequest(data));
                            break;
                        case FunctionCode.WriteSingleCoil:
                            Handle(new WriteSingleCoilRequest(data));
                            break;
                        case FunctionCode.WriteSingleRegister:
                            Handle(new WriteSingleRegisterRequest(data));
                            break;
                        case FunctionCode.WriteMultipleCoil:
                            Handle(new WriteMultipleCoilRequest(data));
                            break;
                        case FunctionCode.WriteMultipleRegister:
                            Handle(new WriteMultipleRegisterRequest(data));
                            break;
                        case FunctionCode.ReadFileRecord:
                            // Handle(new ReadFileRecordRequest(data));
                            break;
                        case FunctionCode.WriteFileRecord:
                            // Handle(new WriteFileRecordRequest(data));
                            break;
                        case FunctionCode.MaskWriteRegister:
                            //Handle(new MaskWriteRegisterRequest(data));
                            break;
                        case FunctionCode.ReadDeviceId:

                            // Handle(new ReadDeviceIdRequest(data));
                            break;
                        case FunctionCode.Error:

                            // Handle(new ErrorRequest(data));
                            break;
                            //default:
                            //    throw new ArgumentOutOfRangeException();
                    }
                }
                else
                {
                    //没有车型
                }
            }
            else
            {
                //内容不对
            }
            //Show(data);
        }

        public void HandleBase(AbstractModbusMessage message)
        {
            _transmission.Send(message);
        }
        public void Close()
        {
            _transmission.Close();
        } 
        public void Send(AbstractModbusMessage message)
        {
            SendMessageEvent?.Invoke(message.PackingMessage());
            _transmission.Send(message);
        }
        public event Action<byte[]> ReceivedMessageEvent;
        public event Action<byte[]> SendMessageEvent;
        
        public event Action<ReadCoilRequest> ReadCoilEvent;
        private void Handle(ReadCoilRequest message)
        {
            ReadCoilEvent?.Invoke(message);
        }

        public event Action<ReadDiscreteInputRequest> ReadDiscreteInputEvent;
        private void Handle(ReadDiscreteInputRequest message)
        {
            ReadDiscreteInputEvent?.Invoke(message);
        }

        public event Action<ReadHoldRegisterRequest> ReadHoldRegisterEvent;

        private void Handle(ReadHoldRegisterRequest message)
        {
            ReadHoldRegisterEvent?.Invoke(message);
        }

        public event Action<ReadInputRegisterRequest> ReadInputRegisterEvent;
        private void Handle(ReadInputRegisterRequest message)
        {
            ReadInputRegisterEvent?.Invoke(message);
        }

        public event Action<WriteSingleCoilRequest> WriteSingleCoilEvent;

        private void Handle(WriteSingleCoilRequest message)
        {
            WriteSingleCoilEvent?.Invoke(message);
        }

        public event Action<WriteSingleRegisterRequest> WriteSingleRegisterEvent;

        private void Handle(WriteSingleRegisterRequest message)
        {
            WriteSingleRegisterEvent?.Invoke(message);
        }

        public event Action<WriteMultipleCoilRequest> WriteMultipleCoilEvent;

        private void Handle(WriteMultipleCoilRequest message)
        {
            WriteMultipleCoilEvent?.Invoke(message);
        }

        public event Action<WriteMultipleRegisterRequest> WriteMultipleRegisterEvent;

        private void Handle(WriteMultipleRegisterRequest message)
        {
            WriteMultipleRegisterEvent?.Invoke(message);
        }
    }
}
